package ru.niir.goodfil.ui;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.myfaces.custom.fileupload.UploadedFile;
import ru.goodwill.ExcelTable;
import ru.goodwill.TableModel;
import ru.goodwillexceptions.FileException;
import ru.goodwillexceptions.ModelException;
import ru.goodwillexceptions.ParseException;
import ru.niir.goodfil.db.Good;
import ru.niir.goodfil.exceptions.ValidationException;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static ru.niir.goodfil.utils.Utils.s;

public class ImportGoodsBean extends PageBean {
    private static final Logger logger = Logger.getLogger(ImportGoodsBean.class);

    private static final String TEMP_CATALOG_KEY = ".temp";

    private static final String TEMP_CATALOG_KEY_DEFAULT = "/home/sazonov/temp";

    private static final int STATE_START = 0;

    private static final int STATE_SHOW_BAD_GODOS = 1;

    private static final int STATE_UPLOAD = 2;

    private static final int STATE_PREVIEW = 3;

    private static final int STATE_PREVIEW_NEW = 4;

    private static final int STATE_PREVIEW_OLD = 5;

    private static final int STATE_PREVIEW_CHANGED = 6;

    private static final int STATE_PREVIEW_MISSING = 7;

    private static final int STATE_FINISHED = 8;

    public ImportGoodsBean() {
    }

    private int currentState = STATE_START;

    public int getCurrentState() {
        return currentState;
    }

    public void setCurrentState(int currentState) {
        this.currentState = currentState;
    }

    public boolean getIsStateStart() {
        return currentState == STATE_START;
    }

    public long getIsGoodsCount() {
        return gf().getGoodsCount(null);
    }

    public long getIsBadGoodsCount() {
        return gf().getGoodsCountWithout1C();
    }

    public void showBadGoods() {
        currentState = STATE_SHOW_BAD_GODOS;
    }

    public void showPreviewNew() {
        currentState = STATE_PREVIEW_NEW;
    }

    public void showPreviewOld() {
        currentState = STATE_PREVIEW_OLD;
    }

    public void showPreviewMissing() {
        currentState = STATE_PREVIEW_MISSING;
    }

    public void showPreviewChanged() {
        currentState = STATE_PREVIEW_CHANGED;
    }

    public boolean getIsStateShowBadGoods() {
        return currentState == STATE_SHOW_BAD_GODOS;
    }

    public boolean getIsStateShowUpload() {
        return currentState == STATE_UPLOAD;
    }

    public boolean getIsStatePreview() {
        return currentState == STATE_PREVIEW;
    }

    public boolean getIsStatePreviewNew() {
        return currentState == STATE_PREVIEW_NEW;
    }

    public boolean getIsStatePreviewOld() {
        return currentState == STATE_PREVIEW_OLD;
    }

    public boolean getIsStatePreviewChanged() {
        return currentState == STATE_PREVIEW_CHANGED;
    }

    public boolean getIsStatePreviewMissing() {
        return currentState == STATE_PREVIEW_MISSING;
    }

    public boolean getIsStateFinished() {
        return currentState == STATE_FINISHED;
    }

    public List<Good> getBadGoods() {
        return gf().getBadGoods();
    }

    public void showStart() {
        currentState = STATE_START;
    }

    public void showUpload() {
        currentState = STATE_UPLOAD;
    }

    public void showPreview() {
        currentState = STATE_PREVIEW;
    }

    private UploadedFile uploadedFile;

    public UploadedFile getUploadedFile() {
        return uploadedFile;
    }

    public void setUploadedFile(UploadedFile uploadedFile) {
        this.uploadedFile = uploadedFile;
    }

    private List<Item> items = null;

    private List<Item> list_new = null;

    private List<Item> list_changed = null;

    private List<Item> list_old = null;

    private List<Item> list_missing = null;

    public void reset() {
        currentState = STATE_START;
        list_new = null;
        list_changed = null;
        list_old = null;
        list_missing = null;
    }

    public List<Item> getList_missing() {
        return list_missing;
    }

    public List<Item> getList_old() {
        return list_old;
    }

    public List<Item> getList_changed() {
        return list_changed;
    }

    public List<Item> getList_new() {
        return list_new;
    }

    public int getList_missedSize() {
        return list_missing.size();
    }

    public int getList_oldSize() {
        return list_old.size();
    }

    public int getList_changedSize() {
        return list_changed.size();
    }

    public int getList_newSize() {
        return list_new.size();
    }

    /**
     * Загрузка и разбор файла с товарами из 1С
     */
    public void upload() {
        items = null;

        UUID uid = UUID.randomUUID();

        gf().createIfNotExists(TEMP_CATALOG_KEY, TEMP_CATALOG_KEY_DEFAULT);
        String tempCatalog = gf().get(TEMP_CATALOG_KEY);
        String filePath = tempCatalog + File.separator + uid.toString() + ".xls";
        File f = new File(filePath);
        try {
            InputStream is = uploadedFile.getInputStream();
            OutputStream os = new FileOutputStream(f);
            int c = is.read();
            while (c != -1) {
                os.write(c);
                c = is.read();
            }
            os.flush();
            os.close();

            is.close();

            items = new ArrayList<Item>();
            ExcelTable excelTable = new ExcelTable();
            try {
                TableModel tableModel = excelTable.initTableModel(f, "goodCode1C", 2, 2);
                for (int i = 1; i < tableModel.getRowCount(); i++) {
                    String c1 = tableModel.getValueAt(i, 0);
                    String c2 = tableModel.getValueAt(i, 1);
                    String c3 = tableModel.getValueAt(i, 2);

                    if (StringUtils.isBlank(c1) ||
                            StringUtils.isBlank(c2) ||
                            StringUtils.isBlank(c3)) {
                        facesError("Файл содержит пустые ячейки (строка " + String.valueOf(i + 1) + ")");
                        return;
                    }

                    Item item = new Item(c1, c2, c3);
                    items.add(item);
                }
            } catch (FileException e) {
                facesError("Невозможно прочитать файл");
                e.printStackTrace();
            } catch (ModelException e) {
                facesError("Невозможно разобрать файл");
                e.printStackTrace();
            } catch (ParseException e) {
                facesError("Невозможно обработать файл");
                e.printStackTrace();
            }

            //
            //  Обработка
            //

            list_new = new ArrayList<Item>();
            list_changed = new ArrayList<Item>();
            list_old = new ArrayList<Item>();
            list_missing = new ArrayList<Item>();

            List<Good> goods = gf().getGoods(0, Integer.MAX_VALUE, null);
            for (Good good : goods) {
                if (good.isDeleted()) continue;

                Item item = findItemByISCode(items, good.getCode());
                if (item == null) {
                    Item i = new Item();
                    i.setCodeIS(good.getCode());
                    i.setCode1C_old(good.getC1code());
                    i.setCode1C_new("");
                    i.setNameIS(good.getName());
                    i.setName1С("");

                    list_missing.add(i);
                    continue;
                }

                String old1CCode = good.getC1code();
                String new1CCode = item.getCode1C_new();

                item.setCode1C_old(old1CCode);
                item.setNameIS(good.getName());

                if (old1CCode == null || old1CCode.equals("")) {
                    list_new.add(item);
                    continue;
                }

                if (old1CCode.equals(new1CCode)) {
                    list_old.add(item);
                } else {
                    list_changed.add(item);
                }
            }

            currentState = STATE_PREVIEW;
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }

    private static Item findItemBy1CCode(List<Item> items, String code) {
        code = s(code);

        for (Item item : items) {
            if (item.getCode1C_new().equals(code)) {
                return item;
            }
        }
        return null;
    }

    private static Item findItemByISCode(List<Item> items, String code) {
        code = s(code);

        for (Item item : items) {
            if (item.getCodeIS().toLowerCase().equals(code.toLowerCase())) {
                return item;
            }
        }
        return null;
    }

    public int getItemsSize() {
        return items.size();
    }

    public List<Item> getCurrentPreview() {
        if (currentState == STATE_PREVIEW_NEW) {
            return list_new;
        }

        if (currentState == STATE_PREVIEW_OLD) {
            return list_old;
        }

        if (currentState == STATE_PREVIEW_CHANGED) {
            return list_changed;
        }

        if (currentState == STATE_PREVIEW_MISSING) {
            return list_missing;

        }
        return new ArrayList<Item>();
    }

    public String getCurrentPreviewName() {
        if (currentState == STATE_PREVIEW_NEW) return "Новые коды";
        if (currentState == STATE_PREVIEW_OLD) return "Старые коды";
        if (currentState == STATE_PREVIEW_CHANGED) return "Измененные коды";
        if (currentState == STATE_PREVIEW_MISSING) return "Отсутствующие коды";
        return "";
    }

    public int getCurrentPreviewSize() {
        return getCurrentPreview().size();
    }

    private int updatedSuccessfulyCount = 0;

    private int updatedWithErrorsCount = 0;

    public void apply1CCodes() {
        logger.debug("Applying 1C codes");

        updatedSuccessfulyCount = 0;
        updatedWithErrorsCount = 0;

        for (Item item : items) {
            Good good = gf().getGoodByCode(item.getCodeIS());
            if (good == null) continue;

            String oldCode = good.getC1code();
            String newCode = item.getCode1C_new();
            good.setC1code(item.getCode1C_new());
            try {
                logger.debug("Good " + good.getCode() + " [" + good.getId() + "] `" + oldCode + "` -> `" + newCode + "`...");
                gf().updateGood(good);
                updatedSuccessfulyCount++;
            } catch (ValidationException e) {
                e.printStackTrace();
                logger.error("Good " + good.getCode() + " [" + good.getId() + "] `" + oldCode + "` -> `" + newCode + "`!");
                updatedWithErrorsCount++;
            }
        }
        currentState = STATE_FINISHED;
    }

    public int getUpdatedSuccessfulyCount() {
        return updatedSuccessfulyCount;
    }

    public int getUpdatedWithErrorCount() {
        return updatedWithErrorsCount;
    }

    public static class Item {
        public String code1C_new;

        public String code1C_old;

        public String codeIS;

        public String name1С;

        public String nameIS;

        public Item() {
        }

        public Item(String code1CNew, String codeIS, String name1С, String nameIS) {
            this.code1C_new = s(code1CNew);
            this.codeIS = s(codeIS);
            this.name1С = s(name1С);
            this.nameIS = s(nameIS);
        }

        public Item(String code1CNew, String codeIS, String name1С) {
            setCode1C_new(code1CNew);
            this.codeIS = s(codeIS);
            this.name1С = s(name1С);
        }

        public String getCode1C_new() {
            return code1C_new;
        }

        public void setCode1C_new(String code1C_new) {
            if (StringUtils.isEmpty(code1C_new)) {
                this.code1C_new = "";
                return;
            }

            this.code1C_new = String.valueOf(new Float(Float.parseFloat(s(code1C_new))).intValue());

            //  Пиздец. Убейте меня.
            if (this.code1C_new.length() == 0) this.code1C_new = "00000000";
            if (this.code1C_new.length() == 1) this.code1C_new = "0000000" + this.code1C_new;
            if (this.code1C_new.length() == 2) this.code1C_new = "000000" + this.code1C_new;
            if (this.code1C_new.length() == 3) this.code1C_new = "00000" + this.code1C_new;
            if (this.code1C_new.length() == 4) this.code1C_new = "0000" + this.code1C_new;
            if (this.code1C_new.length() == 5) this.code1C_new = "000" + this.code1C_new;
            if (this.code1C_new.length() == 6) this.code1C_new = "00" + this.code1C_new;
            if (this.code1C_new.length() == 7) this.code1C_new = "0" + this.code1C_new;
        }

        public String getCode1C_old() {
            return code1C_old;
        }

        public void setCode1C_old(String code1C_old) {
            this.code1C_old = code1C_old;
        }

        public String getCodeIS() {
            return codeIS;
        }

        public void setCodeIS(String codeIS) {
            this.codeIS = codeIS;
        }

        public String getName1С() {
            return name1С;
        }

        public void setName1С(String name1С) {
            this.name1С = name1С;
        }

        public String getNameIS() {
            return nameIS;
        }

        public void setNameIS(String nameIS) {
            this.nameIS = nameIS;
        }

        @Override
        public String toString() {
            return "Item{" +
                    "code1C_new='" + code1C_new + '\'' +
                    ", code1C_old='" + code1C_old + '\'' +
                    ", codeIS='" + codeIS + '\'' +
                    ", name1С='" + name1С + '\'' +
                    ", nameIS='" + nameIS + '\'' +
                    '}';
        }
    }
}
